package com.yeskery.nut.extend.openapi;

import com.yeskery.nut.annotation.api.*;
import com.yeskery.nut.annotation.web.*;
import com.yeskery.nut.application.ApplicationType;
import com.yeskery.nut.application.ServerEventContext;
import com.yeskery.nut.bean.NoSuchBeanException;
import com.yeskery.nut.bind.BindObject;
import com.yeskery.nut.bind.FitValueHelper;
import com.yeskery.nut.core.Controller;
import com.yeskery.nut.core.Method;
import com.yeskery.nut.core.*;
import com.yeskery.nut.extend.responsive.JsonResponsive;
import com.yeskery.nut.extend.responsive.JsonResponsivePlugin;
import com.yeskery.nut.plugin.NutApplicationSupportBasePlugin;
import com.yeskery.nut.plugin.ServerEventPlugin;
import com.yeskery.nut.scan.controller.AnnotationControllerInvocationHandler;
import com.yeskery.nut.scan.controller.AnnotationRequestMethodAttributes;
import com.yeskery.nut.util.ReflectUtils;
import com.yeskery.nut.util.StringUtils;

import java.io.ByteArrayInputStream;
import java.lang.reflect.*;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZonedDateTime;
import java.util.*;
import java.util.logging.Logger;
import java.util.stream.Collectors;

/**
 * OpenApi3 插件，自动根据当前controller上的注解信息生成OpenApi3规范的json接口，只能处理注解方式的controller
 * @author sunjay
 * 2023/9/24
 */
public class OpenApi3Plugin extends NutApplicationSupportBasePlugin implements ServerEventPlugin {

    /** 日志对象 */
    private static final Logger logger = Logger.getLogger(OpenApi3Plugin.class.getName());

    /** 默认URI */
    private static final String OPEN_API3_BASE_URI = "/extend/api";

    /** set方法前缀 */
    private static final String SET_METHOD_PREFIX = "set";

    /** 动态controller前缀 */
    private static final String DYNAMIC_CONTROLLER_PREFIX = "$";

    /** 访问URI */
    private final String baseUri;

    /** 数据map */
    private final Map<String, Object> dataMap = new TreeMap<>();

    /** json数据字符串 */
    private volatile String jsonData;

    /**
     * 构建OpenApi3 插件
     */
    public OpenApi3Plugin() {
        this(OPEN_API3_BASE_URI);
    }

    /**
     * 构建OpenApi3 插件
     * @param baseUri 访问基础URI
     */
    public OpenApi3Plugin(String baseUri) {
        this.baseUri = baseUri;
    }

    @Override
    public void beforeStart(ServerEventContext serverEventContext) {
        if (!serverEventContext.getPluginManager().containPlugin(JsonResponsivePlugin.class)) {
            logger.warning("The Plugin[OpenApi3Plugin] Need Depend Plugin[JsonResponsivePlugin].");
            return;
        }
        ApplicationType applicationType = serverEventContext.getApplicationMetadata().getApplicationType();
        if (ApplicationType.isWebApplicationType(applicationType)) {
            dataMap.clear();
            doInitAnnotationControllerApiInfoMetadata(serverEventContext);
            serverEventContext.getControllerManager().registerController(openApi3RequestHandler(), Method.GET, baseUri + "/openapi3");
            logger.info("OpenApi3Plugin[OpenApi3 Preview], Endpoint[" + baseUri + "/openapi3], Alias[], Method[" + Method.GET + "]");
            serverEventContext.getControllerManager().registerController(openApi3DownloadRequestHandler(), Method.GET, baseUri + "/openapi3/download");
            logger.info("OpenApi3Plugin[OpenApi3 Download], Endpoint[" + baseUri + "/openapi3/download], Alias[], Method[" + Method.GET + "]");
        }
    }

    /**
     * OpenApi3端点
     * @return OpenApi3端点处理类
     */
    private RequestHandler openApi3RequestHandler() {
        return (request, response, execution) -> response.writeJson(getJsonData());
    }

    /**
     * OpenApi3下载端点
     * @return OpenApi3下载端点处理类
     */
    private RequestHandler openApi3DownloadRequestHandler() {
        return (request, response, execution) -> {
            response.addHeader("Content-Disposition", "attachment; filename=\"openapi3.json\"");
            response.write(new ByteArrayInputStream(getJsonData().getBytes(StandardCharsets.UTF_8)));
        };
    }

    /**
     * 获取json数据
     * @return json数据
     */
    private String getJsonData() {
        if (jsonData == null) {
            synchronized (this) {
                if (jsonData == null) {
                    jsonData = getApplicationContext().getBean(JsonResponsive.class).getResponsiveConvert().convertTo(dataMap);
                }
            }
        }
        return jsonData;
    }

    /**
     * 执行注解controller api信息的解析
     * @param serverEventContext 服务事件上下文
     */
    private void doInitAnnotationControllerApiInfoMetadata(ServerEventContext serverEventContext) {
        doInitBaseOpenApiInfoMetadata();
        List<Object> tagsList = new ArrayList<>();
        Map<String, Object> pathsMap = new TreeMap<>();
        Map<String, Object> schemasMap = new TreeMap<>();
        for (Map.Entry<ControllerMetadata, Controller> entry : serverEventContext.getControllerManager().getAllController().entrySet()) {
            if (ControllerSource.ANNOTATION == entry.getKey().getControllerSource()) {
                doInitApiInfoMetadata(tagsList, entry.getKey(), (AnnotationControllerInvocationHandler) Proxy.getInvocationHandler(entry.getValue()),
                        pathsMap, schemasMap);
            }
        }
        if (!tagsList.isEmpty()) {
            dataMap.put("tags", tagsList);
        }
        if (!pathsMap.isEmpty()) {
            dataMap.put("paths", pathsMap);
        }
        if (!schemasMap.isEmpty()) {
            Map<String, Object> componentMap = new TreeMap<>();
            componentMap.put("schemas", schemasMap);
            dataMap.put("components", componentMap);
        }
    }

    /**
     * 处理基础OpenApi信息
     */
    private void doInitBaseOpenApiInfoMetadata() {
        try {
            dataMap.put("openapi", "3.0.3");
            OpenApi3Metadata openApi3Metadata = getApplicationContext().getBean(OpenApi3Metadata.class);
            Map<String, Object> infoMap = new TreeMap<>();
            if (StringUtils.isEmpty(openApi3Metadata.getTitle())) {
                infoMap.put("title", "The Nut Api Doc - OpenApi3");
            } else {
                infoMap.put("title", openApi3Metadata.getTitle());
            }
            if (StringUtils.isEmpty(openApi3Metadata.getDescription())) {
                infoMap.put("description", "This is default nut doc with OpenApi3.");
            } else {
                infoMap.put("description", openApi3Metadata.getDescription());
            }
            if (!StringUtils.isEmpty(openApi3Metadata.getTermsOfService())) {
                infoMap.put("termsOfService", openApi3Metadata.getTermsOfService());
            }
            if (!StringUtils.isEmpty(openApi3Metadata.getContactEmail())) {
                Map<String, String> contactMap = new TreeMap<>();
                contactMap.put("email", openApi3Metadata.getContactEmail());
                infoMap.put("contact", contactMap);
            }
            if (!StringUtils.isEmpty(openApi3Metadata.getLicenseName()) || !StringUtils.isEmpty(openApi3Metadata.getLicenseUrl())) {
                Map<String, String> licenseMap = new TreeMap<>();
                if (!StringUtils.isEmpty(openApi3Metadata.getLicenseName())) {
                    licenseMap.put("name", openApi3Metadata.getLicenseName());
                }
                if (!StringUtils.isEmpty(openApi3Metadata.getLicenseUrl())) {
                    licenseMap.put("url", openApi3Metadata.getLicenseUrl());
                }
                infoMap.put("license", licenseMap);
            }
            if (StringUtils.isEmpty(openApi3Metadata.getVersion())) {
                infoMap.put("version", Version.VERSION);
            } else {
                infoMap.put("version", openApi3Metadata.getVersion());
            }
            dataMap.put("info", infoMap);
            if (!StringUtils.isEmpty(openApi3Metadata.getExternalDocsDescription()) || !StringUtils.isEmpty(openApi3Metadata.getExternalDocsUrl())) {
                Map<String, String> externalDocsMap = new TreeMap<>();
                if (!StringUtils.isEmpty(openApi3Metadata.getExternalDocsDescription())) {
                    externalDocsMap.put("description", openApi3Metadata.getExternalDocsDescription());
                }
                if (!StringUtils.isEmpty(openApi3Metadata.getExternalDocsUrl())) {
                    externalDocsMap.put("url", openApi3Metadata.getExternalDocsUrl());
                }
                dataMap.put("externalDocs", externalDocsMap);
            }
            if (openApi3Metadata.getServerUrls() != null && !openApi3Metadata.getServerUrls().isEmpty()) {
                dataMap.put("services", openApi3Metadata.getServerUrls());
            }
        } catch (NoSuchBeanException e) {
            doInitDefaultBaseOpenApiInfoMetadata();
        }
    }

    /**
     * 使用默认的基础OpenApi信息
     */
    private void doInitDefaultBaseOpenApiInfoMetadata() {
        Map<String, Object> infoMap = new TreeMap<>();
        infoMap.put("title", "The Nut Api Doc - OpenApi3");
        infoMap.put("description", "This is default nut doc with OpenApi3.");
        infoMap.put("termsOfService", "https://gitee.com/yeskery/nut");
        Map<String, String> contactMap = new TreeMap<>();
        contactMap.put("email", "dusj128@hotmail.com");
        infoMap.put("contact", contactMap);
        Map<String, String> licenseMap = new TreeMap<>();
        licenseMap.put("name", "MIT License");
        licenseMap.put("url", "http://opensource.org/licenses/MIT");
        infoMap.put("license", licenseMap);
        infoMap.put("version", Version.VERSION);
        dataMap.put("info", infoMap);
        Map<String, String> externalDocsMap = new TreeMap<>();
        externalDocsMap.put("description", "Find more for nut.");
        externalDocsMap.put("url", "https://gitee.com/yeskery/nut");
        dataMap.put("externalDocs", externalDocsMap);
    }

    /**
     * 执行api信息解析
     * @param tagsList tag集合
     * @param controllerMetadata controller元数据
     * @param handler 注解controller处理器
     * @param pathsMap 路径map
     * @param schemasMap 接口map
     */
    private void doInitApiInfoMetadata(List<Object> tagsList, ControllerMetadata controllerMetadata, AnnotationControllerInvocationHandler handler,
                                       Map<String, Object> pathsMap, Map<String, Object> schemasMap) {
        Class<?> controllerClass = null;
        ApiGroup apiGroup = null;
        for (Map.Entry<Method, AnnotationRequestMethodAttributes> entry : handler.getAnnotationMethodHandleMap().entrySet()) {
            if (controllerClass == null) {
                controllerClass = entry.getValue().getType();
                if (controllerClass == null) {
                    return;
                }
                apiGroup = controllerClass.getAnnotation(ApiGroup.class);
                if (apiGroup == null) {
                    return;
                }
                tagsList.add(getTagMap(apiGroup));
            }
            if (!entry.getValue().getMethod().isAnnotationPresent(Api.class)) {
                continue;
            }
            if (entry.getKey() == Method.ALL) {
                Set<Method> methodSet = new HashSet<>(Arrays.asList(Method.GET, Method.POST, Method.PUT, Method.DELETE));
                doInitControllerApiInfoMetadata(apiGroup, controllerMetadata, methodSet, entry.getValue(), pathsMap, schemasMap);
                break;
            }
            doInitControllerApiInfoMetadata(apiGroup, controllerMetadata, Collections.singleton(entry.getKey()), entry.getValue(), pathsMap, schemasMap);
        }
    }

    /**
     * 获取Tag Map
     * @param apiGroup api分组注解
     * @return Tag Map
     */
    private Map<String, Object> getTagMap(ApiGroup apiGroup) {
        Map<String, Object> tagMap = new TreeMap<>();
        tagMap.put("name", apiGroup.value());
        String description;
        tagMap.put("description", StringUtils.isEmpty(description = apiGroup.description()) ? apiGroup.value() : description);
        if (!StringUtils.isEmpty(apiGroup.externalDocsDescription()) || !StringUtils.isEmpty(apiGroup.externalDocsUrl())) {
            Map<String, String> externalDocMap = new TreeMap<>();
            if (!StringUtils.isEmpty(apiGroup.externalDocsDescription())) {
                externalDocMap.put("description", apiGroup.externalDocsDescription());
            }
            if (!StringUtils.isEmpty(apiGroup.externalDocsUrl())) {
                externalDocMap.put("url", apiGroup.externalDocsUrl());
            }
            tagMap.put("externalDocs", externalDocMap);
        }
        return tagMap;
    }

    /**
     * 执行api controller信息解析
     * @param apiGroup api分组名称注解
     * @param controllerMetadata controller元数据
     * @param methodSet 支持的方法集合
     * @param attributes 属性
     * @param pathsMap 路径map
     * @param schemasMap 接口map
     */
    private void doInitControllerApiInfoMetadata(ApiGroup apiGroup, ControllerMetadata controllerMetadata,
                                                 Set<Method> methodSet, AnnotationRequestMethodAttributes attributes,
                                                 Map<String, Object> pathsMap, Map<String, Object> schemasMap) {
        java.lang.reflect.Method controllerMethod = attributes.getMethod();
        if (!controllerMethod.isAnnotationPresent(ResponseBody.class) && !attributes.getType().isAnnotationPresent(RestController.class)) {
            return;
        }
        String path = controllerMetadata.getPath();
        if (path.startsWith(DYNAMIC_CONTROLLER_PREFIX)) {
            if (path.trim().equals(DYNAMIC_CONTROLLER_PREFIX)) {
                return;
            }
            path = path.substring(DYNAMIC_CONTROLLER_PREFIX.length());
        }
        Api api = controllerMethod.getAnnotation(Api.class);
        Map<String, Object> pathMethodMap = new TreeMap<>();
        for (Method method : methodSet) {
            Map<String, Object> methodMap = new TreeMap<>();
            methodMap.put("tags", Collections.singletonList(apiGroup.value()));
            methodMap.put("summary", api.value());
            methodMap.put("description", api.description());
            methodMap.put("operationId", controllerMethod.getName() + controllerMetadata.getId());
            List<Object> parameterList = new ArrayList<>();
            for (Parameter parameter : controllerMethod.getParameters()) {
                ApiIgnore apiIgnore = parameter.getAnnotation(ApiIgnore.class);
                if (apiIgnore != null && apiIgnore.value()) {
                    continue;
                }
                if (parameter.isAnnotationPresent(RequestBody.class)) {
                    if (!doInitComponentSchemaInfoMetadata(parameter.getType(), schemasMap)) {
                        continue;
                    }
                    Map<String, Object> requestBodyMap = new TreeMap<>();
                    ApiModel apiModel = parameter.getType().getAnnotation(ApiModel.class);
                    if (apiModel != null) {
                        requestBodyMap.put("description", apiModel.value());
                    }
                    Map<String, Object> contentMap = new TreeMap<>();
                    Map<String, Object> jsonMap = new HashMap<>();
                    if (FitValueHelper.getInstance().isBasicTypeClass(parameter.getType())) {
                        jsonMap.put("schema", Collections.singletonMap("type", getBasicClassType(parameter.getType())));
                    } else {
                        jsonMap.put("schema", Collections.singletonMap("$ref", "#/components/schemas/" + parameter.getType().getSimpleName()));
                    }
                    contentMap.put("application/json", jsonMap);
                    requestBodyMap.put("content", contentMap);
                    requestBodyMap.put("required", true);
                    methodMap.put("requestBody", requestBodyMap);
                } else if (parameter.isAnnotationPresent(RequestParam.class)) {
                    doQueryParameterInfoMetadata(true, parameter, parameterList);
                } else if (parameter.isAnnotationPresent(PathVariable.class)) {
                    if (!FitValueHelper.getInstance().isBasicTypeClass(parameter.getType())) {
                        continue;
                    }
                    PathVariable pathVariable = parameter.getAnnotation(PathVariable.class);
                    String name = StringUtils.isEmpty(pathVariable.value()) ? parameter.getName() : pathVariable.value();
                    parameterList.add(getQueryMetadata(parameter.getType(), name, "path", parameter.getAnnotation(ApiParam.class)));
                } else if (MultipartFile.class.isAssignableFrom(parameter.getType())) {
                    Map<String, Object> streamMap = new TreeMap<>();
                    Map<String, Object> schemaMap = new TreeMap<>();
                    schemaMap.put("type", "string");
                    schemaMap.put("format", "binary");
                    streamMap.put("schema", schemaMap);
                    methodMap.put("requestBody", Collections.singletonMap("content", Collections.singletonMap("application/octet-stream", streamMap)));
                } else {
                    if (FitValueHelper.getInstance().isBasicTypeClass(parameter.getType())) {
                        doQueryParameterInfoMetadata(false, parameter, parameterList);
                    } else {
                        if (!doInitComponentSchemaInfoMetadata(parameter.getType(), schemasMap)) {
                            continue;
                        }
                        Map<String, Object> formMap = new TreeMap<>();
                        Map<String, Object> schemaMap = Collections.singletonMap("$ref", "#/components/schemas/" + parameter.getType().getSimpleName());
                        formMap.put("schema", schemaMap);
                        methodMap.put("requestBody", Collections.singletonMap("content", Collections.singletonMap("application/x-www-form-urlencoded", formMap)));
                    }
                }
            }
            if (!parameterList.isEmpty()) {
                methodMap.put("parameters", parameterList);
            }
            Map<String, Object> successMap = new TreeMap<>();
            Class<?> clazz = void.class.equals(api.responseClass()) ? controllerMethod.getReturnType() : api.responseClass();
            ApiModel apiModel = clazz.getAnnotation(ApiModel.class);
            if (apiModel != null && !StringUtils.isEmpty(apiModel.value())) {
                successMap.put("description", apiModel.value());
            }
            Map<String, Object> jsonMap = new TreeMap<>();
            if (FitValueHelper.getInstance().isBasicTypeClass(clazz)) {
                jsonMap.put("schema", Collections.singletonMap("type", getBasicClassType(clazz)));
            } else {
                if (!doInitComponentSchemaInfoMetadata(clazz, schemasMap)) {
                    continue;
                }
                jsonMap.put("schema", Collections.singletonMap("$ref", "#/components/schemas/" + clazz.getSimpleName()));
            }
            successMap.put("content", Collections.singletonMap("application/json", jsonMap));
            methodMap.put("responses", Collections.singletonMap("200", successMap));
            pathMethodMap.put(method.name().toLowerCase(), methodMap);
        }
        if (pathMethodMap.isEmpty()) {
            return;
        }
        pathsMap.put(path, pathMethodMap);
    }

    /**
     * 处理查询参数元数据
     * @param valid 是否需要验证
     * @param parameter 参数对象
     * @param parameterList 参数集合
     */
    private void doQueryParameterInfoMetadata(boolean valid, Parameter parameter, List<Object> parameterList) {
        if (valid && !FitValueHelper.getInstance().isBasicTypeClass(parameter.getType())) {
            return;
        }
        RequestParam requestParam = parameter.getAnnotation(RequestParam.class);
        String name = StringUtils.isEmpty(requestParam.value()) ? parameter.getName() : requestParam.value();
        parameterList.add(getQueryMetadata(parameter.getType(), name, "query", parameter.getAnnotation(ApiParam.class)));
    }

    /**
     * 获取查询参数元数据
     * @param clazz 类型
     * @param name 名称
     * @param query 类型
     * @param apiParam api参数注解
     * @return 查询参数元数据
     */
    private Object getQueryMetadata(Class<?> clazz, String name, String query, ApiParam apiParam) {
        Map<String, Object> parameterMap = new TreeMap<>();
        parameterMap.put("name", name);
        parameterMap.put("query", query);
        if (apiParam != null && !StringUtils.isEmpty(apiParam.value())) {
            parameterMap.put("description", apiParam.value());
        }
        parameterMap.put("schema", Collections.singletonMap("type", ReflectUtils.getDefaultBeanName(clazz.getSimpleName())));
        return parameterMap;
    }

    /**
     * 处理实体类数据
     * @param clazz 实体类对象
     * @param schemasMap 规范map
     */
    private boolean doInitComponentSchemaInfoMetadata(Class<?> clazz, Map<String, Object> schemasMap) {
        if (schemasMap.containsKey(clazz.getSimpleName())) {
            return true;
        }
        if (clazz.equals(Object.class) || FitValueHelper.getInstance().isBasicTypeClass(clazz)) {
            return false;
        }
        List<java.lang.reflect.Method> methodList = Arrays.stream(ReflectUtils.getBeanMethods(clazz))
                .filter(m -> {
                    int modifiers = m.getModifiers();
                    return !Modifier.isStatic(modifiers) && !Modifier.isAbstract(modifiers) && Modifier.isPublic(modifiers);
                }).filter(m -> m.getName().startsWith(SET_METHOD_PREFIX))
                .filter(m -> m.getName().length() > SET_METHOD_PREFIX.length())
                .filter(m -> m.getParameterCount() == 1)
                .collect(Collectors.toList());
        if (methodList.isEmpty()) {
            return false;
        }
        Field[] fields = ReflectUtils.getBeanAllField(clazz);
        Map<String, Object> componentMap = new TreeMap<>();
        componentMap.put("type", "object");
        Map<String, Object> propertiesMap = new TreeMap<>();
        List<String> requiredPropertyList = new ArrayList<>();
        for (java.lang.reflect.Method method : methodList) {
            String propertyName = method.getName().substring(SET_METHOD_PREFIX.length());
            propertyName = ReflectUtils.getDefaultBeanName(propertyName);
            final String fieldName = propertyName;
            Optional<Field> optional = Arrays.stream(fields).filter(f -> f.getName().equals(fieldName)).findFirst();
            if (!optional.isPresent()) {
                continue;
            }
            ApiModelProperty apiModelProperty = optional.get().getAnnotation(ApiModelProperty.class);
            if (apiModelProperty != null && apiModelProperty.ignore()) {
                continue;
            }
            ApiIgnore apiIgnore = optional.get().getAnnotation(ApiIgnore.class);
            if (apiIgnore != null && apiIgnore.value()) {
                continue;
            }
            Class<?> parameterClass = method.getParameters()[0].getType();
            Map<String, Object> propertyMap = doInitComponentPropertySchemaInfoMetadata(parameterClass,
                    method.getParameters()[0].getParameterizedType(), propertyName, apiModelProperty, schemasMap);
            if (propertyMap == null) {
                continue;
            }
            if (apiModelProperty != null && apiModelProperty.required()) {
                requiredPropertyList.add(propertyName);
            }
            propertiesMap.put(propertyName, propertyMap);
        }
        if (propertiesMap.isEmpty()) {
            return false;
        }
        if (!requiredPropertyList.isEmpty()) {
            componentMap.put("required", requiredPropertyList);
        }
        componentMap.put("properties", propertiesMap);
        schemasMap.put(clazz.getSimpleName(), componentMap);
        return true;
    }

    /**
     * 处理实体字段
     * @param parameterClass 参数类型
     * @param parameterizedType 参数类型
     * @param propertyName 字段名称
     * @param apiModelProperty api字段注解
     * @param schemasMap 规范map
     * @return 处理后的实体字段map
     */
    private Map<String, Object> doInitComponentPropertySchemaInfoMetadata(Class<?> parameterClass, Type parameterizedType, String propertyName,
                                                                          ApiModelProperty apiModelProperty, Map<String, Object> schemasMap) {
        Map<String, Object> propertyMap = new TreeMap<>();
        if (apiModelProperty != null && !StringUtils.isEmpty(apiModelProperty.value())) {
            propertyMap.put("description", apiModelProperty.value());
        }
        if (parameterClass == Array.class || List.class.isAssignableFrom(parameterClass)) {
            propertyMap = new TreeMap<>();
            propertyMap.put("type", "array");

            Type type;
            if ((type = parameterizedType) instanceof ParameterizedType) {
                Class<?> rawClass = (Class<?>) ((ParameterizedType) type).getRawType();
                if (FitValueHelper.getInstance().isBasicTypeClass(rawClass)) {
                    Map<String, Object> itemMap = doInitComponentPropertySchemaInfoMetadata(rawClass, rawClass, propertyName, apiModelProperty, schemasMap);
                    if (itemMap == null) {
                        return null;
                    }
                    propertyMap.put("items", itemMap);
                } else {
                    if (!doInitComponentSchemaInfoMetadata(rawClass, schemasMap)) {
                        return null;
                    }
                    propertyMap.put("items", Collections.singletonMap("$ref", "#/components/schemas/" + rawClass.getSimpleName()));
                }
            }
        } else {
            if (FitValueHelper.getInstance().isBasicTypeClass(parameterClass)) {
                propertyMap.put("type", getBasicClassType(parameterClass));
                if (apiModelProperty != null && !StringUtils.isEmpty(apiModelProperty.example())) {
                    BindObject bindObject = FitValueHelper.getInstance().getFitParamValue(propertyName, apiModelProperty.example(), parameterClass);
                    if (!bindObject.isEmpty()) {
                        propertyMap.put("example", bindObject.getData());
                    }
                }
            } else if (Arrays.asList(Date.class, java.sql.Date.class, LocalDate.class, LocalDateTime.class, ZonedDateTime.class).contains(parameterClass)) {
                propertyMap.put("type", "string");
                propertyMap.put("format", "date-time");
                if (apiModelProperty != null && !StringUtils.isEmpty(apiModelProperty.example())) {
                    BindObject bindObject = FitValueHelper.getInstance().getFitParamValue(propertyName, apiModelProperty.example(), parameterClass);
                    if (!bindObject.isEmpty()) {
                        propertyMap.put("example", bindObject.getData());
                    }
                }
            } else {
                if (!doInitComponentSchemaInfoMetadata(parameterClass, schemasMap)) {
                    return null;
                }
                propertyMap.put("$ref", "#/components/schemas/" + parameterClass.getSimpleName());
            }
        }
        return propertyMap;
    }

    /**
     * 获取基础类型的openapi类型
     * @param clazz 基础类
     * @return 对应的openapi类型
     */
    private String getBasicClassType(Class<?> clazz) {
        if (String.class == clazz) {
            return ReflectUtils.getDefaultBeanName(String.class.getSimpleName());
        } else if (boolean.class == clazz || Boolean.class == clazz) {
            return ReflectUtils.getDefaultBeanName(Boolean.class.getSimpleName());
        } else if (byte.class == clazz || Byte.class == clazz || short.class == clazz || Short.class == clazz
                || int.class == clazz || Integer.class == clazz || long.class == clazz || Long.class == clazz) {
            return ReflectUtils.getDefaultBeanName(Integer.class.getSimpleName());
        } else if (float.class == clazz || Float.class == clazz || double.class == clazz || Double.class == clazz || BigDecimal.class == clazz) {
            return ReflectUtils.getDefaultBeanName(Number.class.getSimpleName());
        }
        return ReflectUtils.getDefaultBeanName(clazz.getSimpleName());
    }
}
